package com.stek.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.support.v4.content.AsyncTaskLoader;

import com.stek.model.AppInfo;
import com.stek.utils.AppUtils;
import com.stek.utils.Logging;

public class AppLoader extends AsyncTaskLoader<List<AppInfo>> {
	public static final int FILTER_ALL_APPS = 0;
	public static final int FILTER_APPS_RUNNING = FILTER_ALL_APPS + 1;
	public static final int FILTER_SYSTEMS_APPS = FILTER_ALL_APPS + 2;
	public static final int FILTER_APPS_SDCARD = FILTER_ALL_APPS + 3;
	public static final int FILTER_USER_APPS = FILTER_ALL_APPS + 4;
	private PackageManager mPm;
	private List<AppInfo> mApps;
	private int mFlag = -1;

	private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			onContentChanged();

		}
	};

	public AppLoader(Context context) {
		super(context);
		mPm = context.getPackageManager();
		registerAppChanges();
	}

	public void setFlag(int mFlag) {
		this.mFlag = mFlag;
	}

	private void registerAppChanges() {
		IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
		filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
		filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
		filter.addDataScheme("package");
		getContext().registerReceiver(mBroadcastReceiver, filter);
	}

	private void unregisterAppChanges() {
		// Stop monitoring for changes.
		try {
			getContext().unregisterReceiver(mBroadcastReceiver);
		} catch (Exception e) {
		}
	}

	@Override
	public List<AppInfo> loadInBackground() {
		List<ApplicationInfo> installedAppList = mPm
				.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
						| PackageManager.GET_DISABLED_COMPONENTS);
		return fillerApp(installedAppList);

	}

	public List<AppInfo> fillerApp(List<ApplicationInfo> installedAppList) {
		List<AppInfo> appList = new ArrayList<AppInfo>();
		String ownPgk = getContext().getPackageName();
		if (mFlag == FILTER_APPS_SDCARD) {
			for (ApplicationInfo appInfo : installedAppList) {
				if ((appInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0
						&& mPm.getLaunchIntentForPackage(appInfo.packageName) != null
						&& !ownPgk.equals(appInfo.packageName)) {
					appList.add(new AppInfo(appInfo.packageName, AppUtils
							.getApplicationLabel(getContext(), appInfo),
							AppUtils.getApplicationIcon(getContext(), appInfo),
							(appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0,
							appInfo.sourceDir));
				}
			}
		} else if (mFlag == FILTER_SYSTEMS_APPS) {
			for (ApplicationInfo appInfo : installedAppList) {
				if (((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 || (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)
						&& mPm.getLaunchIntentForPackage(appInfo.packageName) != null
						&& !ownPgk.equals(appInfo.packageName)) {
					appList.add(new AppInfo(appInfo.packageName, AppUtils
							.getApplicationLabel(getContext(), appInfo),
							AppUtils.getApplicationIcon(getContext(), appInfo),
							(appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0,
							appInfo.sourceDir));
				}
			}
		} else if (mFlag == FILTER_USER_APPS) {
			for (ApplicationInfo appInfo : installedAppList) {
				if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
						&& mPm.getLaunchIntentForPackage(appInfo.packageName) != null
						&& !ownPgk.equals(appInfo.packageName)) {
					appList.add(new AppInfo(appInfo.packageName, AppUtils
							.getApplicationLabel(getContext(), appInfo),
							AppUtils.getApplicationIcon(getContext(), appInfo),
							(appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0,
							appInfo.sourceDir));
				}
			}
		} else {
			for (ApplicationInfo appInfo : installedAppList) {
				if (mPm.getLaunchIntentForPackage(appInfo.packageName) != null
						&& !ownPgk.equals(appInfo.packageName)) {
					appList.add(new AppInfo(appInfo.packageName, AppUtils
							.getApplicationLabel(getContext(), appInfo),
							AppUtils.getApplicationIcon(getContext(), appInfo),
							(appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0,
							appInfo.sourceDir));
				}
			}
		}
		Collections.sort(appList, new Comparator<AppInfo>() {

			@Override
			public int compare(AppInfo lhs, AppInfo rhs) {
				return lhs.name.compareTo(rhs.name);
			}
		});
		return appList;
	}

	/**
	 * Called when there is new data to deliver to the client. The super class
	 * will take care of delivering it; the implementation here just adds a
	 * little more logic.
	 */
	@Override
	public void deliverResult(List<AppInfo> apps) {
		if (isReset()) {
			// An async query came in while the loader is stopped. We
			// don't need the result.
			if (apps != null) {
				onReleaseResources(apps);
			}
		}
		List<AppInfo> oldApps = mApps;
		mApps = apps;
		if (isStarted()) {
			// If the Loader is currently started, we can immediately
			// deliver its results.
			super.deliverResult(apps);
		}

		// At this point we can release the resources associated with
		// 'oldApps' if needed; now that the new result is delivered we
		// know that it is no longer in use.
		if (oldApps != null) {
			onReleaseResources(oldApps);
		}
		super.deliverResult(apps);
	}

	/**
	 * Handles a request to start the Loader.
	 */
	@Override
	protected void onStartLoading() {
		if (mApps != null) {
			// If we currently have a result available, deliver it
			// immediately.
			deliverResult(mApps);
		}

		if (takeContentChanged() || mApps == null) {
			// If the data has changed since the last time it was loaded
			// or is not currently available, start a load.
			forceLoad();
		}
	}

	/**
	 * Handles a request to stop the Loader.
	 */
	@Override
	protected void onStopLoading() {
		Logging.log("onStopLoading");
		// Attempt to cancel the current load task if possible.
		cancelLoad();
	}

	/**
	 * Handles a request to cancel a load.
	 */
	@Override
	public void onCanceled(List<AppInfo> apps) {
		super.onCanceled(apps);
		// At this point we can release the resources associated with 'apps'
		// if needed.
		unregisterAppChanges();
		onReleaseResources(apps);
	}

	/**
	 * Handles a request to completely reset the Loader.
	 */
	@Override
	protected void onReset() {
		Logging.log("onReset");
		super.onReset();

		// Ensure the loader is stopped
		onStopLoading();

		// At this point we can release the resources associated with 'apps'
		// if needed.
		if (mApps != null) {
			onReleaseResources(mApps);
			mApps = null;
		}

	
	}

	/**
	 * Helper function to take care of releasing resources associated with an
	 * actively loaded data set.
	 */
	protected void onReleaseResources(List<AppInfo> apps) {
		// For a simple List<> there is nothing to do. For something
		// like a Cursor, we would close it here.
	}

}
